#include "self_flash_drv.h"


/**
 * @desc  : 读取内部flash数据
 * @date  : 2025-04-26
 * @author: AnRui
 * @param : readAddr - {参数说明}:  读取地址
 * @param : pBuffer - {参数说明}:   数组首地址
 * @param : numToRead - {参数说明}: 要读出数据的个数
 * @return:
 * @note  :
 */
bool FlashRead(uint32_t readAddr, uint8_t* pBuffer, uint32_t numToRead) {
    if ((readAddr + numToRead - 1) > FLASH_END_ADDRESS) {
        printf("1ww");
        return  false;
    }
    if (readAddr < FLASH_START_ADDRESS) {
        printf("2ww");
        return false;
    }
    if (pBuffer == NULL) {
        printf("3ww");
        return false;
    }
    if (numToRead == 0) {
        printf("4ww");
        return false;
    }
    for (uint32_t i = 0; i < numToRead; i++) {
        *pBuffer = *(uint8_t*)readAddr;
        readAddr++;
        pBuffer++;
    }
    return true;
}




/**
 * @desc  :擦除从eraseAddr开始到eraseAddr + numToErase的页
 * @date  : 2025-04-26
 * @author: AnRui
 * @param : eraseAddr - {参数说明}: 地址
 * @param : numToErase - {参数说明}: 对应写入数据时的个数
 * @return: true
 * @note  :
 */
static bool FlashErase(uint32_t eraseAddr, uint32_t numToErase) {
    // 检测
    if (numToErase == 0 || (eraseAddr + numToErase - 1) > FLASH_END_ADDRESS) {
        return false;
    }

    uint8_t pageNum = 0;
    // mod运算求余在一页内的偏移,若eraseAddr是FLASH_PAGE_SIZE整数倍,运算结果为0
    uint8_t addrOffset = eraseAddr % FLASH_PAGE_SIZE;
    // 剩余空间
    uint32_t reaminSpace = FLASH_PAGE_SIZE - addrOffset;

    //记录状态 解锁
    fmc_state_enum fmcState = FMC_READY;
    fmc_unlock();

    if (numToErase > reaminSpace)           // 跨页
    {
        fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR);
        fmcState = fmc_page_erase(eraseAddr);           // 擦本页
        if (fmcState != FMC_READY) {
            goto erase_err;
        }

        // 对齐到下一页地址
        eraseAddr += reaminSpace;
        // 剩余数量
        numToErase -= reaminSpace;

        pageNum = numToErase / FLASH_PAGE_SIZE;
        pageNum += (numToErase % FLASH_PAGE_SIZE) == 0 ? 0 : 1;
        while (pageNum--) {
            fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR);
            fmcState = fmc_page_erase(eraseAddr);
            if (fmcState != FMC_READY) {
                goto erase_err;
            }
            eraseAddr += FLASH_PAGE_SIZE;
        }
    } else {
        fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR);
        fmcState = fmc_page_erase(eraseAddr);
        if (fmcState != FMC_READY) {
            goto erase_err;
        }
    }
    /* lock the main FMC after the erase operation */
    fmc_lock();
    return true;

erase_err:
    /* lock the main FMC after the erase operation */
    fmc_lock();
    return false;
}



/**
 * @desc  : 指定地址开始写入指定个数的数据
 * @date  : 2025-04-26
 * @author: AnRui
 * @param : writeAddr - {参数说明}: 写入地址
 * @param : pBuffer - {参数说明}: 数组首地址
 * @param : numToWrite - {参数说明}: 要写入的数据个数
 * @note  : 注意:因为是2个字节写入 所以保证开始的写入地址 必须为2的倍数
 */
bool FlashWrite(uint32_t writeAddr, uint8_t* pBuffer, uint32_t numToWrite) {
    // 检测
    if ((writeAddr + numToWrite - 1) > FLASH_END_ADDRESS) {
        return false;
    }

    // 半字(2字节)写入,地址要对齐
    if (writeAddr % 2 == 1) {
        return false;
    }

    if (!FlashErase(writeAddr, numToWrite)) {
        return false;
    }


    uint16_t temp;
    fmc_state_enum  fmcState = FMC_READY;
    fmc_unlock();

    for (uint32_t i = 0; i < numToWrite / 2; i++) {
        fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR);
        // 一次性写入两个字节的数据
        fmcState = fmc_halfword_program(writeAddr, *(uint16_t*)pBuffer);
        if (fmcState != FMC_READY) {
            goto erase_err;
        }
        pBuffer += 2;
        writeAddr += 2;
    }
    if (numToWrite % 2) {
        fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR);
        temp = *pBuffer | 0xff00;
        fmcState = fmc_halfword_program(writeAddr, temp);
        if (fmcState != FMC_READY) {
            goto erase_err;
        }
    }

    fmc_lock();
    return true;
erase_err:
    /* lock the main FMC after the erase operation */
    fmc_lock();
    return false;
}

/**
 * @desc  : 内部flash 读写测试
 * @date  : 2025-04-27
 * @author: AnRui
 * @note  :
 */
void FlashDrvTest(void) {
    uint32_t BUFFER_SIZE = 100;
    uint32_t FLASH_TEST_ADDRESS = 0x0807F004;
    uint8_t bufferWrite[BUFFER_SIZE];
    uint8_t bufferRead[BUFFER_SIZE];

    printf("flash writing data:\n");
    for (uint16_t i = 0; i < BUFFER_SIZE; i++) {
        bufferWrite[i] = i + 1;
        // printf("0x%02X ", bufferWrite[i]);
    }
    printf("\n start write\n");

    if (!FlashWrite(FLASH_TEST_ADDRESS, bufferWrite, BUFFER_SIZE)) {
        printf("Flash write error,please check!\n");
        return;
    }

    printf("read start \n");
    if (!FlashRead(FLASH_TEST_ADDRESS, bufferRead, BUFFER_SIZE)) {
        printf("Flash read error,please check!\n");
        return;
    }
    for (uint16_t i = 0; i < BUFFER_SIZE; i++) {
        if (bufferRead[i] != bufferWrite[i]) {
            printf("0x%02X ", bufferRead[i]);
            printf("Flash test error,please check!\n");
            return;
        }
        printf("0x%02X ", bufferRead[i]);

    }
    printf("\nFlash test success!\n");
}
